package cn.jaye.fabric.domain.service;

import cn.jaye.fabric.common.constants.GlobalConstant;
import cn.jaye.fabric.common.constants.exception.OrgExceptionEnum;
import cn.jaye.fabric.common.constants.mapping.Config;
import cn.jaye.fabric.common.constants.mapping.Table;
import cn.jaye.fabric.common.model.ServiceException;
import cn.jaye.fabric.domain.model.MChannel;
import cn.jaye.fabric.domain.model.MPeer;
import cn.jaye.fabric.domain.model.Org;
import cn.jaye.fabric.domain.model.SampleUser;
import cn.jaye.fabric.domain.repository.OrdererRepository;
import cn.jaye.fabric.domain.repository.OrgRepository;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.exception.TransactionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Set;

/**
 * @author Jaye
 * @create 2018-05-07 17:07
 */
@Service
public class ChannelSerivce {


    @Autowired
    private HFClient hfClient;

    @Autowired
    private UserService userService;

    @Autowired
    private GlobalConstant globalConstant;

    @Autowired
    private OrdererService ordererService;

    @Autowired
    private PeerService peerService;

    @Autowired
    private ConfigService configService;

    public Channel getChannel(String channelName, Org org, String[] peerIds) throws Exception {
//        Channel channel = hfClient.getChannel(channelName);
        Channel channel = hfClient.newChannel(channelName);
//        if (channel == null) {
//            channel = hfClient.newChannel(channelName);
//        }

        configService.setChannel(channel);
        Collection<Orderer> orderers = ordererService.getOrderers(org);
        addPeer(channel, peerService.getPeersByPeerIds(org, peerIds));
        addOrderer(channel, orderers);
//        addEventHub(channel, peerService.getEventHubsByPeerIds(org, peerIds));
        if (!channel.isInitialized()) {
            channel.initialize();
        }
        return channel;
    }

    public Channel getChannel(String channelName, Org org) throws Exception {
        Channel channel = hfClient.newChannel(channelName);
        configService.setChannel(channel);
        Collection<Orderer> orderers = ordererService.getOrderers(org);
        addPeer(channel, peerService.getPeerByChannel(channelName));
        addOrderer(channel, orderers);
//        addEventHub(channel, peerService.getEventHubsByChannel(channelName));
        if (!channel.isInitialized()) {
            channel.initialize();
        }
        return channel;
    }


    public Channel constructChannel(MChannel mChannel, Org org, String[] peerIds) throws Exception {
        SampleUser peerAdmin = userService.getSampleAdmin(org.getOrgName(), org.getMspId(), org.getDomainName());
        hfClient.setUserContext(peerAdmin);
        Collection<Orderer> orderers = ordererService.getOrderers(org);
        Orderer anOrderer = orderers.iterator().next();
        orderers.remove(anOrderer);
        ChannelConfiguration channelConfiguration = new ChannelConfiguration(getChannelConfiguration(mChannel.getChannelName(), mChannel.getTxPath()));
        Channel newChannel = hfClient.newChannel(mChannel.getChannelName(), anOrderer, channelConfiguration, hfClient.getChannelConfigurationSignature(channelConfiguration, peerAdmin));
        configService.setChannel(newChannel);
        joinPeer(newChannel, peerService.getPeersByPeerIds(org, peerIds));
        addOrderer(newChannel, orderers);
        addEventHub(newChannel, peerService.getEventHubsByPeerIds(org, peerIds));
        newChannel.initialize();
        return newChannel;
    }

    //    private String
    private void joinPeer(Channel channel, Collection<Peer> peers) throws ProposalException {
        for (Peer peer : peers) {
            channel.joinPeer(peer);
        }
    }

    private void addPeer(Channel channel, Collection<Peer> peers) throws InvalidArgumentException {
        for (Peer peer : peers) {
            channel.addPeer(peer);
        }
    }

    private void addOrderer(Channel channel, Collection<Orderer> orderers) throws InvalidArgumentException {
        for (Orderer orderer : orderers) {
            channel.addOrderer(orderer);
        }
    }

    private void addEventHub(Channel channel, Collection<EventHub> eventHubs) throws InvalidArgumentException {
        for (EventHub eventHub : eventHubs) {
            channel.addEventHub(eventHub);
        }
    }

    private File getChannelConfiguration(String channelName, String txPath) {
        if (StringUtils.isBlank(txPath)) {
            txPath = globalConstant.getChannel().get(Config.Channel.defaultTxPath.getKey());
        }
        if (StringUtils.isBlank(channelName)) {
            channelName = globalConstant.getChannel().get(Config.Channel.defaultName);
        }
        File file = new File(txPath + "/" + channelName + ".tx");
        return file;
    }

    public Channel createChannel() {
        return null;
    }

    public Channel getChannelByRelPeer(String channelName, Org org) throws InvalidArgumentException, TransactionException {
        Channel channel = hfClient.newChannel(channelName);
        configService.setChannel(channel);
        Collection<Orderer> orderers = ordererService.getOrderers(org);
        addPeer(channel, peerService.getPeerByChannel(channelName));
        addOrderer(channel, orderers);
//        addEventHub(channel, peerService.getEventHubsByChannel(channelName));
        if (!channel.isInitialized()) {
            channel.initialize();
        }
        return channel;
    }
}
